package 多线程;

import java.util.concurrent.Semaphore;

/**
 * 该类用于实现多个线程的循环打印。
 * 使用Semaphore实现线程间的同步，确保按顺序打印。
 * 时间复杂度：O(n)，空间复杂度：O(1)
 */
public class LoopPrinter {
    private final static int THREAD_COUNT = 3; // 线程数量
    static int result = 0; // 打印结果
    static int maxNum = 10; // 最大打印次数

    /**
     * 主方法，启动多个线程进行循环打印。
     * @param args 命令行参数
     * @throws InterruptedException 如果线程被中断
     */
    public static void main(String[] args) throws InterruptedException {
        final Semaphore[] semaphores = new Semaphore[THREAD_COUNT]; // 信号量数组
        for(int i = 0; i < THREAD_COUNT; i++) {
            //非公平信号量，每个信号量初始计数都为1
            semaphores[i] = new Semaphore(1); // 初始化信号量
            if(i != THREAD_COUNT - 1) {
                System.out.println(i + "===" + semaphores[i].getQueueLength()); // 打印当前信号量的等待队列长度
                //获取一个许可前线程将一直阻塞, for 循环之后只有 syncObjects[2] 没有被阻塞
                semaphores[i].acquire(); // 获取信号量
            }
        }
        for(int i = 0; i < THREAD_COUNT; i++) {
            // 初次执行，上一个信号量是 syncObjects[2]
            final Semaphore lastSemaphore = i == 0 ? semaphores[THREAD_COUNT - 1] : semaphores[i - 1]; // 上一个信号量
            final Semaphore currentSemaphore = semaphores[i]; // 当前信号量
            final int index = i; // 当前线程索引
            new Thread(() -> {
                try {
                    while(true) {
                        // 初次执行，让第一个 for 循环没有阻塞的 syncObjects[2] 先获得令牌阻塞了
                        lastSemaphore.acquire(); // 获取上一个信号量
                        System.out.println("thread" + index + ":" + result++); // 打印当前线程和结果
                        if(result > maxNum) {
                            System.exit(0); // 如果结果超过最大打印次数，退出程序
                        }
                        // 释放当前的信号量，syncObjects[0] 信号量此时为 1，下次 for 循环中上一个信号量即为syncObjects[0]
                        currentSemaphore.release(); // 释放当前信号量
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start(); // 启动线程
        }
    }
}
